package api

import (
    "errors"
    "math"
    "strconv"
    "strings"
    
    "github.com/gin-gonic/gin"
    "gorm.io/gorm"
    
    "collecter/app/common/enum"
    "collecter/app/common/helper"
    "collecter/app/common/service"
    "collecter/app/controller"
    "collecter/app/model"
)

type CollectController struct {
    controller.BaseController
}


func (c *CollectController) List(ctx *gin.Context) {
    var categoryId int64
    /* 搜索条件 */
    if val, err := strconv.Atoi(controller.Ctx.DefaultQuery("cate_id", "")); err != nil {
        // c.FormatReturn(enum.FAILED, "", err.Error())
        var user model.Users
        if val, err := c.GetUserInfo(); err != nil {
            c.FormatReturn(enum.FAILED, "", err.Error())
        } else {
            user = *val
        }
        var categoryService service.CategoryService
        categoryService.UserId = user.Id
        if category, err := categoryService.UserDefaultCategory(); err != nil {
            c.FormatReturn(enum.FAILED, "", err.Error())
        } else {
            categoryId = category.Id
        }
    } else {
        categoryId = int64(val)
    }
    title := controller.Ctx.Query("title")
    contentType := controller.Ctx.Query("content_type")
    
    if categoryId <= 0 {
        c.FormatReturn(6, "")
    }
    var user model.Users
    if val, err := c.GetUserInfo(); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    } else {
        user = *val
    }
    
    category := model.Categorys{Id: categoryId, UserId: user.Id}
    if err := helper.Db.Where(&category).First(&category).Error; err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            c.FormatReturn(enum.FAILED, "", "该分类不属于当前用户")
        }
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    
    collects := make([]*model.Collects, 0, 0)
    query := helper.Db.Where("status = 1 and category_id = ? and user_id = ?", categoryId, user.Id)
    if len(title) > 0 {
        query.Where("title like %?%", title)
    }
    if len(contentType) > 0 {
        query.Where("content_type = ?", contentType)
    }
    allQuery := query
    allQuery.Model(&model.Collects{})
    var allCount, pageCount int64
    if err := allQuery.Count(&allCount).Error; err != nil {
        c.FormatReturn(enum.FAILED, "", query.Error.Error())
    }
    pageCount = int64(math.Ceil(float64(allCount) / float64(controller.Limit)))
    offset := (controller.Page - 1) * controller.Limit
    query.Order("created_at desc").Limit(controller.Limit).Offset(offset).Find(&collects)
    if query.Error != nil {
        c.FormatReturn(enum.FAILED, "", query.Error.Error())
    }
    if len(collects) > 0 {
        for idx, val := range collects {
            if val.ContentType == 2 {
                collects[idx].Content = strings.TrimRight(helper.Configer.GetString("domain"), "/") + "/" + strings.Trim(val.Content, "/")
            }
        }
    }
    contentTypeMap := map[int]string{1: "文字", 2: "文件", 3: "url"}
    rst := map[string]any{
        "page": controller.Page,
        "limit": controller.Limit,
        "all_count": allCount,
        "page_count": pageCount,
        "list": collects,
        "content_type_map": contentTypeMap,
    }
    
    c.FormatReturn(enum.SUCCESS, rst)
}


func (c *CollectController) Create(ctx *gin.Context) {
    type inType struct {
        CategoryId  int64  `json:"category_id,omitempty"`
        Title       string `json:"title,omitempty"`
        Description string `json:"description,omitempty"`
        Content     string `json:"content,omitempty"`
        ContentType int8   `json:"content_type,omitempty"`
    }
    var inData inType
    if err := controller.Ctx.BindJSON(&inData); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    if len(inData.Content) == 0 || len(inData.Title) > 255 || len(inData.Description) > 255 {
        c.FormatReturn(6, "")
    }
    if len(inData.Title) == 0 {
        inData.Title = "user-collect"
    }
    if inData.ContentType == 0 {
        inData.ContentType = 1
    }
    var user model.Users
    if val, err := c.GetUserInfo(); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    } else {
        user = *val
    }
    if inData.CategoryId == 0 {
        var categoryService service.CategoryService
        categoryService.UserId = user.Id
        if category, err := categoryService.UserDefaultCategory(); err != nil {
            c.FormatReturn(enum.FAILED, "", err.Error())
        } else {
            inData.CategoryId = category.Id
        }
    }
    cs := service.NewCollectService()
    cs.UserId = user.Id
    cs.CategoryId = inData.CategoryId
    cs.Title = inData.Title
    cs.Description = inData.Description
    cs.Content = inData.Content
    cs.ContentType = inData.ContentType
    if err := cs.Create(); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    c.FormatReturn(enum.SUCCESS, "")
}

func (c *CollectController) Update(ctx *gin.Context) {
    type inType struct {
        Id          int64  `json:"id,omitempty"`
        UserId      int64  `json:"user_id,omitempty"`
        CategoryId  int64  `json:"category_id,omitempty"`
        Title       string `json:"title,omitempty"`
        Description string `json:"description,omitempty"`
        Content     string `json:"content,omitempty"`
    }
    var inData inType
    if err := controller.Ctx.BindJSON(&inData); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    if inData.Id == 0 || len(inData.Title) > 255 || len(inData.Description) > 255 {
        c.FormatReturn(6, "")
    }
    var user model.Users
    if val, err := c.GetUserInfo(); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    } else {
        user = *val
    }
    cs := service.NewCollectService()
    cs.Id = inData.Id
    cs.UserId = user.Id
    cs.CategoryId = inData.CategoryId
    cs.Title = inData.Title
    cs.Description = inData.Description
    cs.Content = inData.Content
    if err := cs.Update(); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    c.FormatReturn(enum.SUCCESS, "")
}

func (c *CollectController) Delete(ctx *gin.Context) {
    type inType struct {
        Id int64 `json:"id,omitempty"`
    }
    var inData inType
    if err := controller.Ctx.BindJSON(&inData); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    var user model.Users
    if val, err := c.GetUserInfo(); err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    } else {
        user = *val
    }
    
    collect := model.Collects{Id: inData.Id, UserId: user.Id}
    if err := helper.Db.Where(&collect).First(&collect).Error; err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) {
            c.FormatReturn(enum.FAILED, "", "收藏记录不存在")
        }
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    if err := helper.Db.Delete(&collect).Error; err != nil {
        c.FormatReturn(enum.FAILED, "", err.Error())
    }
    otherCollect := model.Collects{Abstract: collect.Abstract}
    if err := helper.Db.Where(&otherCollect).First(&otherCollect).Error; err != nil {
        if errors.Is(err, gorm.ErrRecordNotFound) && 2 == collect.ContentType {
            // 如果删除的收藏记录其收藏的内容是文件，而且该文件没有其他的收藏记录使用，则删除
            _ = helper.Unlink(collect.Content)
        }
    }
    c.FormatReturn(enum.SUCCESS, "")
}